/**
**********************************************************************
* @file     main.c
* @brief    对文件的简要说明
* @details  对文件的详细说明
* @author   jcai
* @date     2022-05-06 09:30:10
* @copyright Copyright &copy; 2022 wy1107412334@163.com All rights reserved
* @version  v0.0.1
*
* \n Email:  wy1107412334@163.com
* \n Blog:   None
* \n Github: https://github.com/wy1107412334
* \n Gitee:  https://gitee.com/git.git1107412334.com
*
**********************************************************************
* @note
* None.
**********************************************************************
* @attention
* None.
**********************************************************************
@verbatim
@endverbatim
**********************************************************************
* @par 历史记录
* 1. v0.0.1: jcai, 2022-05-06 09:30:10
*   - 首次编写
*
*<center>Copyright &copy; 2022 wy1107412334@163.com All rights reserved</center>
**********************************************************************
*/

/* 头文件导入区 --------------------------------------------------- */

#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <SDL/SDL.h>
#include <SDL/SDL_video.h>
#include <SDL/SDL_ttf.h>
#include <SDL/SDL_image.h>
#include <SDL/SDL_events.h>
#include <SDL/SDL_timer.h>
#include <SDL/SDL_keysym.h>
#include <SDL/SDL_keyboard.h>


typedef struct
{
    int startTicks;
    int pausedTicks;
    int paused;
    int started;
} Timer_t;

typedef struct
{
    SDL_Surface *bitmap;
    SDL_Rect chars[256];
    int newLine;
    int space;
} BitmapFont_t;

// 窗口属性
const int SCREEN_WIDTH = 640;
const int SCREEN_HEIGHT = 480;
const int SCREEN_BPP = 32;

// 帧速率
const int FRAMES_PER_SECOND = 20;

// 将要使用的表面
SDL_Surface *bitmapFont = NULL;
SDL_Surface *screen = NULL;

// 事件结构体
SDL_Event event;



SDL_Surface *load_image(const char *file)
{
    SDL_Surface *loadedImage = NULL;
    SDL_Surface *optimizedImage = NULL;

    // 通过 SDL_imag 模块加载图片
    loadedImage = IMG_Load(file);
    if (!loadedImage)   return NULL;

    optimizedImage = SDL_DisplayFormat(loadedImage);
    SDL_FreeSurface(loadedImage);
    if (optimizedImage)
    {
        // 映射关键色
        uint32_t keycolor = SDL_MapRGB(optimizedImage->format, 0, 0xff, 0xff);
        // 将所有颜色为 RGB(0x00, 0xff, 0xff) 的像素设为透明
        SDL_SetColorKey(optimizedImage, SDL_SRCCOLORKEY, keycolor);
    }

    return optimizedImage;
}

void apply_surface(int x, int y, SDL_Surface *src, SDL_Surface *dst,
                   const SDL_Rect *clip)
{
    SDL_Rect offset;

    offset.x = x;
    offset.y = y;

    SDL_BlitSurface(src, (SDL_Rect *)clip, dst, &offset);
}

int init()
{
    if (SDL_Init(SDL_INIT_EVERYTHING) == -1)
        return -1;

    screen = SDL_SetVideoMode(SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_BPP,
                              SDL_SWSURFACE);
    if (!screen)
    {
        SDL_Quit();
        return -2;
    }

    SDL_WM_SetCaption("Bitmap font Test", NULL);

    return 0;
}

int load_files()
{
    // 加载图片
    bitmapFont = load_image("lazyfont.png");
    if (!bitmapFont)
    {
        return -1;
    }

    return 0;
}

void clean_up()
{
    SDL_FreeSurface(bitmapFont);

    SDL_Quit();
}


uint32_t get_pixel32(int x, int y, SDL_Surface *surface)
{
    uint32_t *pixels = (uint32_t *)surface->pixels;
    return pixels[y * surface->w + x];
}

void BitmapFont_Init(BitmapFont_t *bf)
{
    bf->bitmap = NULL;
    bf->newLine = 0;
    bf->space = 0;
}
static void BitmapFont_build_font(BitmapFont_t *bf, SDL_Surface *surface)
{
    uint32_t bgColor;
    uint32_t cellW, cellH;
    int top, baseA;
    int currentChar;
    int rows, cols;
    int i;

    //If surface is NULL
    if(surface == NULL)   return;

    //Get the bitmap
    bf->bitmap = surface;

    //Set the background color
    bgColor = SDL_MapRGB(bf->bitmap->format, 0, 0xFF, 0xFF);

    //Set the cell dimensions
    cellW = bf->bitmap->w / 16;
    cellH = bf->bitmap->h / 16;

    //New line variables
    top = cellH;
    baseA = cellH;

    //The current character we're setting
    currentChar = 0;

    //Go through the cell rows
    for(rows = 0; rows < 16; rows++)
    {
        int pCol, pRow;

        //Go through the cell columns
        for(cols = 0; cols < 16; cols++)
        {
            //Set the character offset
            bf->chars[currentChar].x = cellW * cols;
            bf->chars[currentChar].y = cellH * rows;

            //Set the dimensions of the character
            bf->chars[currentChar].w = cellW;
            bf->chars[currentChar].h = cellH;

            //Find Left Side
            //Go through pixel columns
            for(pCol = 0; (uint32_t) pCol < cellW; pCol++)
            {
                //Go through pixel rows
                for(pRow = 0; (uint32_t) pRow < cellH; pRow++)
                {
                    //Get the pixel offsets
                    int pX = (cellW * cols) + pCol;
                    int pY = (cellH * rows) + pRow;

                    //If a non colorkey pixel is found
                    if( get_pixel32( pX, pY, bf->bitmap ) != bgColor )
                    {
                        //Set the x offset
                        bf->chars[currentChar].x = pX;

                        //Break the loops
                        pCol = cellW;
                        pRow = cellH;
                    }
                }
            }

            //Find Right Side
            //Go through pixel columns
            for(pCol = cellW - 1; pCol >= 0; pCol--)
            {
                //Go through pixel rows
                for(pRow = 0; (uint32_t) pRow < cellH; pRow++)
                {
                    //Get the pixel offsets
                    int pX = ( cellW * cols ) + pCol;
                    int pY = ( cellH * rows ) + pRow;

                    //If a non colorkey pixel is found
                    if( get_pixel32( pX, pY, bf->bitmap ) != bgColor )
                    {
                        //Set the width
                        bf->chars[ currentChar ].w = ( pX - bf->chars[ currentChar ].x ) + 1;

                        //Break the loops
                        pCol = -1;
                        pRow = cellH;
                    }
                }
            }

            //Find Top
            //Go through pixel rows
            for(pRow = 0; (uint32_t) pRow < cellH; pRow++)
            {
                //Go through pixel columns
                for(pCol = 0; (uint32_t) pCol < cellW; pCol++)
                {
                    //Get the pixel offsets
                    int pX = ( cellW * cols ) + pCol;
                    int pY = ( cellH * rows ) + pRow;

                    //If a non colorkey pixel is found
                    if( get_pixel32( pX, pY, bf->bitmap ) != bgColor )
                    {
                        //If new top is found
                        if( pRow < top )
                        {
                            top = pRow;
                        }

                        //Break the loops
                        pCol = cellW;
                        pRow = cellH;
                    }
                }
            }

            //Find Bottom of A
            if( currentChar == 'A' )
            {
                //Go through pixel rows
                for(pRow = cellH - 1; pRow >= 0; pRow--)
                {
                    //Go through pixel columns
                    for(pCol = 0; (uint32_t) pCol < cellW; pCol++)
                    {
                        //Get the pixel offsets
                        int pX = ( cellW * cols ) + pCol;
                        int pY = ( cellH * rows ) + pRow;

                        //If a non colorkey pixel is found
                        if( get_pixel32( pX, pY, bf->bitmap ) != bgColor )
                        {
                            //Bottom of a is found
                            baseA = pRow;

                            //Break the loops
                            pCol = cellW;
                            pRow = -1;
                        }
                    }
                }
            }

            //Go to the next character
            currentChar++;
        }
    }

    //Calculate space
    bf->space = cellW / 2;

    //Calculate new line
    bf->newLine = baseA - top;

    //Lop off excess top pixels
    for(i = 0; i < 256; i++ )
    {
        bf->chars[i].y += top;
        bf->chars[i].h -= top;
    }
}
void BitmapFont_InitSurface(BitmapFont_t *bf, SDL_Surface *surface)
{
    BitmapFont_build_font(bf, surface);
}
void BitmapFont_ShowText(BitmapFont_t *bf, int x, int y, const char *text,
                         SDL_Surface *surface)
{
    int X = x, Y = y;
    int i, len;

    if (!bf->bitmap || !text)   return;

    len = strlen(text);
    for (i = 0; i < len; i++)
    {
        if (*(text + i) == ' ')
        {
            X += bf->space;
        }
        else if (*(text + i) == '\n')
        {
            Y += bf->newLine;
            X = x;
        }
        else
        {
            int ascii = *(text + i) & 0xff;

            apply_surface(X, Y, bf->bitmap, surface, &bf->chars[ascii]);
            X += bf->chars[ascii].w + 1;
        }
    }
}


void timer_init(Timer_t *tm)
{
    tm->startTicks = 0;
    tm->pausedTicks = 0;
    tm->paused = 0;
    tm->started = 0;
}
void timer_start(Timer_t *tm)
{
    tm->started = 1;
    tm->paused = 0;

    tm->startTicks = SDL_GetTicks();
}
void timer_stop(Timer_t *tm)
{
    tm->started = 0;
}
void timer_pause(Timer_t *tm)
{
    if (tm->started && !tm->paused)
    {
        tm->paused = 1;
        tm->pausedTicks = SDL_GetTicks() - tm->startTicks;
    }
}
void timer_unpause(Timer_t *tm)
{
    if (tm->paused)
    {
        tm->paused = 0;

        tm->startTicks = SDL_GetTicks() - tm->pausedTicks;
        tm->pausedTicks = 0;
    }
}
int timer_get_ticks(Timer_t *tm)
{
    if (tm->started)
    {
        if (tm->paused)
            return tm->pausedTicks;
        else
            return SDL_GetTicks() - tm->startTicks;
    }
    return 0;
}
int timer_is_started(Timer_t *tm)
{
    return tm->started;
}
int timer_is_paused(Timer_t *tm)
{
    return tm->paused;
}


/**
**********************************************************************
* @brief    简要说明
* @details  详细说明
* @param    none
* @param[in]     a: 该参数用于输入
* @param[in,out] b: 该参数用于输入和输出
* @param[out]    c: 该参数用于输出
* @retval  none
* @retval  0 函数成功
* @retval  1 函数失败
* @return  返回0成功；否则失败
* @note    none
*/
int main(int argc, char *argv[])
{
    BitmapFont_t font;
    Timer_t fps;
    int quit = 0;

    if (init() != 0)
    {
        fprintf(stderr, "SDL初始化失败\n");
        return EXIT_FAILURE;
    }

    if (load_files() != 0)
    {
        fprintf(stderr, "SDL加载 background.png 失败\n");
        return EXIT_FAILURE;
    }

    BitmapFont_InitSurface(&font, bitmapFont);

    SDL_FillRect(screen, &screen->clip_rect,
                 SDL_MapRGB(screen->format, 0xff, 0xff, 0xff));

    BitmapFont_ShowText(&font, 100, 100,
                        "Bitmap Font:\n"
                        "ABDCEFGHIJKLMNOPQRSTUVWXYZ\n"
                        "abcdefghijklmnopqrstuvwxyz\n"
                        "0123456789", screen);

    timer_init(&fps);

    while (!quit)
    {
        timer_start(&fps);

        // 处理SDL的事件
        while (SDL_PollEvent(&event))
        {
            // 如果用户点击了窗口右上角的关闭按钮
            if (event.type == SDL_QUIT)
            {
                quit = 1;
                printf("处理退出事件\n");
            }
        }


        // 更新窗口
        if (SDL_Flip(screen) == -1)
        {
            fprintf(stderr, "SDL更新窗口失败\n");
            break;
        }

        // 控制帧速率
        if (timer_get_ticks(&fps) < (1000 / FRAMES_PER_SECOND))
            SDL_Delay((1000 / FRAMES_PER_SECOND) - timer_get_ticks(&fps));
    }

    clean_up();

    return 0;
}


/***  Copyright (C) 2022 wy1107412334@163.com All rights reserved ***/
/****************************** END OF FILE *************************/

